/**
 * @file    win32/win32_mutex.h
 * @brief   
 *
 ****************************************************************************
 * @version $Id: win32_mutex.h 2861 2010-08-07 02:42:53Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_WIN32_win32_mutex_H__
 #define __WOSH_Core_WIN32_win32_mutex_H__

 #include <woshDefs.h>
 #include <windows.h>


class Mutex_win32
 {
	public:
		/**
		 * @brief   Empty constructor. Initialize the Mutex
		 */
		Mutex_win32() {
			this->mux = ::CreateMutex( NULL, FALSE, NULL );
		 }

		/**
		 * @brief   Empty destructor. Destroy the Mutex
		 */
		virtual ~Mutex_win32() {
			if ( this->mux != NULL )
				::CloseHandle( this->mux );
		 }

	public:
		/**
		 * @brief   Lock the Mutex (does not check if Mutex was already locked)
		 * @note    check function pthread_mutex_lock() for more info
		 * @note    check function QMutex::lock() for more info
		 */
		inline void lock() const {
			DWORD d = WaitForSingleObject( this->mux, INFINITE );
			(void)d;
		 }
		/**
		 * @brief   UnLock the Mutex (does not check if Mutex was locked)
		 * @note    check function pthread_mutex_unlock() for more info
		 * @note    check function QMutex::unlock() for more info
		 */
		inline void unLock() const {
			::ReleaseMutex( this->mux );
		 }
		/**
		 * @brief   Try locking the Mutex and return response
		 * @note    check function pthread_mutex_trylock() for more info
		 */
		inline bool tryLock() const {
			NOT_IMPLEMENTED();
			return false;
		 }

	private:
		Mutex( const Mutex& ) { }
		const Mutex& operator=( const Mutex& ) { return *this; }

	protected:
		HANDLE mux;

}; // class def


class MutexRW_win32
 {
	public:
		/**
		 * @brief   Empty constructor.
		 */
		MutexRW_win32() {
			this->readersCount = 0;
			InitializeCriticalSection(&this->secionLockWriter);
			InitializeCriticalSection(&this->secionReaderCount);
			// writer event with manual reset and default signaled state
			//  - Signaled = Writer has currently not access
			//  - Non-signaled = Writer has currently access, block readers
			this->eventWriter = CreateEvent( NULL, TRUE, TRUE, NULL );
			// no-readers event with manual reset and default signaled state
			//  - Signaled = No readers have currently access
			//  - Non-signaled = Some readers have currently access, block writer
			this->eventNoReadersm_hNoReadersEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
		 }
		/**
		 * @brief   Empty destructor.
		 */
		virtual ~MutexRW_win32() {
			// free critical sections
			DeleteCriticalSection(&this->secionLockWriter);
			DeleteCriticalSection(&this->secionReaderCount);
			// close handles
			CloseHandle(this->eventWriter);
			CloseHandle(this->eventNoReaders);
		 }

	public:

		inline void lockForRead() const {
			while(true) {
				// wait for Writer event to be signaled
				WaitForSingleObject(this->eventWriter, INFINITE);
				// increment readers
				changeReadersCount(true);
				// If writer is become non-signaled fall back (double locking)
				if ( WaitForSingleObject(this->eventWriter, 0) != WAIT_OBJECT_0 ) {
					// decrement readers
					changeReadersCount(false);
				 }
				else // done
					break;
			}
		 }

		inline void lockForWrite() const {
			// enter critical section (prevent more than one writer)
			EnterCriticalSection(&this->secionLockWriter);
			// wait for current writer
			WaitForSingleObject(this->eventWriter, INFINITE);
			// set writer to non-signaled
			ResetEvent(this->eventWriter);
			// wait for current readers to finish
			WaitForSingleObject(this->eventNoReaders, INFINITE); 
			// leave critical section
			LeaveCriticalSection(&this->secionLockWriter);
		 }

		/**
		 * @brief   UnLock the Mutex (does not check if Mutex was locked)
		 * @note    check function QMutex::unlock() for more info
		 */
		inline void unLock() const {
			if ( this->lockedWrite ) {
				// unLock Write: signal writer event
				SetEvent(this->eventWriter);
			 }
			else {
				// unLock Read: decrement readers
				changeReadersCount(false);
			 }
		 }



		inline bool tryLockForRead() const {
			NOT_IMPLEMENTED( "" );
			return false;
		 }

		inline bool tryLockForWrite() const {
			NOT_IMPLEMENTED();
			return false;
		 }

	private:
		/**
		 * @brief   Empty private copy-constructor.
		 */
		MutexRW_win32( const MutexRW_win32& ) { }
		/**
		 * @brief   Empty private assignement-operator.
		 */
		const MutexRW_win32& operator=( const MutexRW_win32& ) {
			return *this;
		 }

	protected:
		HANDLE eventWriter;			///< writer access event
		HANDLE eventNoReaders;		///< no readers event
		CRITICAL_SECTION secionLockWriter;	///< critical section for protecting lock writer method.
		CRITICAL_SECTION secionReaderCount;	///< critical section for protecting reader count
		int readersCount;			///< number of readers
		bool lockedWrite;			///< currently read/write access

		/// increment/decrement number of readers
		void changeReadersCount( bool increment ) {
			EnterCriticalSection(&this->secionReaderCount);
			if ( increment ) {
				// increase
				this->readersCount++;
				 ResetEvent(this->eventNoReaders);
			 }
			else {
				// decrease
				this->readersCount--;
				if( this->readersCount <= 0 ) {
					SetEvent(this->eventNoReaders);
				 }
			 }
			LeaveCriticalSection(&this->secionReaderCount);
		 }

}; // class def


 
#endif //__WOSH_Core_WIN32_win32_mutex_H__
